package com.sise.recomder;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sise.entity.ProductBrowseRecord;
import com.sise.entity.ProductInfo;
import com.sise.entity.User;
import com.sise.mapper.ProductBrowseRecordMapper;
import com.sise.mapper.ProductInfoMapper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.TreeSet;

/**
 * @author zj
 */
@Service
public class BrowseRecordRecomder {

    @Resource
    private PublicUse publicUse;

    @Resource
    private ProductInfoMapper productInfoMapper;

    @Resource
    private ProductBrowseRecordMapper productBrowseRecordMapper;

    public List<ProductInfo> recommend(String open_id) {
        List<ProductBrowseRecord> productBrowseRecordList;

        List<User> userList = publicUse.getUserList();
        List<ProductInfo> productInfoList = publicUse.getProductInfoList();
        int[][] curMatrix = new int[productInfoList.size() + 5][productInfoList.size() + 5];
        int[][] comMatrix = new int[productInfoList.size() + 5][productInfoList.size() + 5];
        int[] N = new int[productInfoList.size() + 5];

        for (User user : userList) {
            if (user.getOpenId().equals(open_id)) continue;

            QueryWrapper<ProductBrowseRecord> productCollectQueryWrapper = new QueryWrapper<>();
            productCollectQueryWrapper.lambda().eq(ProductBrowseRecord::getOpenId, user.getOpenId());
            productBrowseRecordList = productBrowseRecordMapper.selectList(productCollectQueryWrapper);

            for (int i = 0; i < productInfoList.size(); i++)
                for (int j = 0; j < productInfoList.size(); j++)
                    curMatrix[i][j] = 0;

            for (int i = 0; i < productBrowseRecordList.size(); i++) {
                int pid1 = productBrowseRecordList.get(i).getProductId();
                ++N[pid1];
                for (int j = i + 1; j < productBrowseRecordList.size(); j++) {
                    int pid2 = productBrowseRecordList.get(j).getProductId();
                    ++curMatrix[pid1][pid2];
                    ++curMatrix[pid2][pid1];
                }
            }

            for (int i = 0; i < productInfoList.size(); i++) {
                for (ProductInfo productInfo : productInfoList) {
                    int pid1 = productInfoList.get(i).getProductId(), pid2 = productInfo.getProductId();
                    comMatrix[pid1][pid2] += curMatrix[pid1][pid2];
                    comMatrix[pid1][pid2] += curMatrix[pid1][pid2];
                }
            }
        }

        TreeSet<ProductInfo> preList = publicUse.preprocessingList();

        QueryWrapper<ProductBrowseRecord> productCollectQueryWrapper = new QueryWrapper<>();
        productCollectQueryWrapper.lambda().eq(ProductBrowseRecord::getOpenId, open_id);
        productBrowseRecordList = productBrowseRecordMapper.selectList(productCollectQueryWrapper);
        boolean[] used = new boolean[productInfoList.size() + 5];
        for (ProductBrowseRecord productBrowseRecord : productBrowseRecordList) {
            int Nij;
            double Wij;
            ProductInfo tmp;

            int i = productBrowseRecord.getProductId();
            for (ProductInfo productInfo : productInfoList) {
                if (productBrowseRecord.getProductId().equals(productInfo.getProductId())) continue;
                int j = productInfo.getProductId();

                Nij = comMatrix[i][j];
                Wij = (double) Nij / Math.sqrt(N[i] * N[j]);

                tmp = productInfoMapper.selectById(productInfo.getProductId());
                tmp.setSimilarity(Wij);

                if (used[tmp.getProductId()]) continue;
                preList.add(tmp);
                used[tmp.getProductId()] = true;
            }
        }
        return publicUse.generateRecommendationResults(preList);
    }
}
